#include "doorbell_wsclient.h"
#include "doorbell_config.h"
#include "esp_log.h"
#include "esp_websocket_client.h"

#define TAG "doorbell_wsclient"

static esp_websocket_client_handle_t image_client = NULL;
static esp_websocket_client_handle_t audio_client = NULL;
static void (*audio_callback)(void *arg, const void *buf, int len) = NULL;
static void *audio_callback_arg = NULL;

static void doorbell_wsclient_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
    switch (event_id)
    {
    case WEBSOCKET_EVENT_BEGIN:
        ESP_LOGI(TAG, "Websocket %s created", handler_args == image_client ? "image" : "audio");
        break;
    case WEBSOCKET_EVENT_CONNECTED:
        ESP_LOGI(TAG, "Websocket %s connected", handler_args == image_client ? "image" : "audio");
        break;
    case WEBSOCKET_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "Websocket %s disconnected", handler_args == image_client ? "image" : "audio");
        break;
    case WEBSOCKET_EVENT_DATA:
        if (data->op_code != 0x02 || handler_args != audio_client)
        {
            break;
        }
        if (audio_callback)
        {
            audio_callback(audio_callback_arg, (const void *)data->data_ptr, data->data_len);
        }
        break;
    case WEBSOCKET_EVENT_ERROR:
        ESP_LOGI(TAG, "Websocket %s error", handler_args == image_client ? "image" : "audio");
        break;
    case WEBSOCKET_EVENT_FINISH:
        ESP_LOGI(TAG, "Websocket %s finish", handler_args == image_client ? "image" : "audio");
        break;
    }
}

void doorbell_wsclient_init(void)
{
    esp_websocket_client_config_t ws_config = {
        .uri = "ws://" SERVER_IP ":" WS_PORT WS_AUDIO_SUFFIX,
    };
    audio_client = esp_websocket_client_init(&ws_config);
    ws_config.uri = "ws://" SERVER_IP ":" WS_PORT WS_IMAGE_SUFFIX;
    image_client = esp_websocket_client_init(&ws_config);

    esp_websocket_register_events(audio_client, WEBSOCKET_EVENT_ANY, doorbell_wsclient_event_handler, (void *)audio_client);
    esp_websocket_register_events(image_client, WEBSOCKET_EVENT_ANY, doorbell_wsclient_event_handler, (void *)image_client);
}

void doorbell_wsclient_deinit(void)
{
    esp_websocket_unregister_events(audio_client, WEBSOCKET_EVENT_ANY, doorbell_wsclient_event_handler);
    esp_websocket_unregister_events(image_client, WEBSOCKET_EVENT_ANY, doorbell_wsclient_event_handler);
    esp_websocket_client_destroy(audio_client);
    esp_websocket_client_destroy(image_client);
}

void doorbell_wsclient_connect(void)
{
    esp_websocket_client_start(audio_client);
    esp_websocket_client_start(image_client);
}

void doorbell_wsclient_disconnect(void)
{
    esp_websocket_client_stop(audio_client);
    esp_websocket_client_stop(image_client);
}

void doorbell_wsclient_send_image(void *buf, int len)
{
    if (esp_websocket_client_is_connected(image_client))
    {
        esp_websocket_client_send_bin(image_client, buf, len, portMAX_DELAY);
    }
}

void doorbell_wsclient_send_audio(void *buf, int len)
{
    if (esp_websocket_client_is_connected(audio_client))
    {
        esp_websocket_client_send_bin(audio_client, buf, len, portMAX_DELAY);
    }
}

void doorbell_wsclient_register_audio_callback(void (*callback)(void *arg, const void *buf, int len), void *arg)
{
    audio_callback = callback;
    audio_callback_arg = arg;
}
